#!/usr/bin/python

#Audio Tools, a module and set of tools for manipulating audio data
#Copyright (C) 2007  Brian Langenberger

#This program is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 2 of the License, or
#(at your option) any later version.

#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.

#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA


import audiotools
import optparse,sys,os,os.path

MAX_CPUS = audiotools.MAX_JOBS

def convert_file(destination_class, destination_filename,
                 source_audiofile, metadata, compression,
                 display_output=True):
    if (display_output):
        print (u"%s -> %s" % \
               (source_audiofile.filename.decode(audiotools.FS_ENCODING),
                destination_filename.decode(audiotools.FS_ENCODING))).encode(
            audiotools.IO_ENCODING)

    try:
        if (isinstance(source_audiofile,audiotools.WaveAudio)):
            #if we're converting from a WAVE file, use from_wave()
            destination_audiofile = destination_class.from_wave(
                destination_filename,
                source_audiofile.filename,
                compression)
        elif (destination_class == audiotools.WaveAudio):
            #if we're converting to a WAVE file, use to_wave()
            source_audiofile.to_wave(destination_filename)
            destination_audiofile = audiotools.WaveAudio(destination_filename)

        elif ((source_audiofile.supports_foreign_riff_chunks()) and
              (destination_class.supports_foreign_riff_chunks())):
            #if both the source and target classes support foreign chunks
            #route the data through a temporary WAVE file
            import tempfile

            temp_wave = tempfile.NamedTemporaryFile(suffix='.wav')
            try:
                source_audiofile.to_wave(temp_wave.name)
                destination_audiofile = destination_class.from_wave(
                    destination_filename,
                    temp_wave.name,
                    compression)
            finally:
                temp_wave.close()

        else:
            #otherwise, route the data through PCM
            destination_audiofile = destination_class.from_pcm(
                destination_filename,
                source_audiofile.to_pcm(),
                compression)

        if (metadata != None):
            destination_audiofile.set_metadata(metadata)
    except audiotools.InvalidFormat,msg:
        print >>sys.stderr,(u"*** %s: %s" % \
                            (source_audiofile.filename.decode(
                             audiotools.FS_ENCODING),
                             str(msg))).encode(audiotools.IO_ENCODING)

if (__name__ == '__main__'):
    parser = optparse.OptionParser(
        '%prog [-t track type ] [-x XMCD file] ' + \
        '[-d directory] [-q quality] ' + \
        '<track 1> [track 2] ...',
        version="Python Audio Tools %s" % (audiotools.VERSION))

    parser.add_option('-x','--xmcd',
                      action='store',
                      type='string',
                      dest='xmcd',
                      help='an XMCD file to get audio metadata from')

    parser.add_option('-d','--dir',
                      action='store',
                      type='string',
                      dest='dir',
                      default='.',
                      help='the directory to store converted audio files')

    parser.add_option('-q','--quality',
                      action='store',
                      type='string',
                      dest='quality',
                      help='the quality to store audio values at')

    parser.add_option('-t','--type',
                      action='store',
                      dest='type',
                      choices=audiotools.TYPE_MAP.keys(),
                      default='wav',
                      help='the type of audio value to convert to')

    parser.add_option('-j','--joint',
                      action='store',
                      type='int',
                      default=MAX_CPUS,
                      dest='max_processes',
                      help='the maximum number of processes to run at a time')

    parser.add_option('-o','--output',
                      action='store',
                      dest='output',
                      help='output filename to use, overriding default and -d')

    parser.add_option('--no-replay-gain',
                      action='store_false',
                      dest='add_replay_gain',
                      default=True,
                      help='do not add ReplayGain metadata to newly created tracks')

    (options,args) = parser.parse_args()

    #get the AudioFile class we are converted to
    AudioType = audiotools.TYPE_MAP[options.type]

    #ensure the selected compression is compatible with that class
    if (options.quality == 'help'):
        if (len(AudioType.COMPRESSION_MODES) > 1):
            print >>sys.stderr,"*** Available compression types for %s:" % \
                  (AudioType.SUFFIX)
            for mode in AudioType.COMPRESSION_MODES:
                print >>sys.stderr,mode
        else:
            print >>sys.stderr,"*** Audio type %s has no compression modes" % \
                  (AudioType.SUFFIX)
        sys.exit(0)
    elif (options.quality == None):
        options.quality = AudioType.DEFAULT_COMPRESSION
    elif (options.quality not in AudioType.COMPRESSION_MODES):
        print >>sys.stderr,"*** \"%s\" is not a supported compression " % \
              (options.quality) + "mode for type \"%s\"" % \
              (AudioType.SUFFIX)
        sys.exit(1)

    #grab the list of AudioFile objects we are converting from
    audiofiles = audiotools.open_files(args)
    if (len(audiofiles) < 1):
        print >>sys.stderr,"*** You must specify at least 1 supported audio file"
        sys.exit(1)

    if (options.max_processes < 1):
        print >>sys.stderr,'*** You must run at least 1 process at a time'
        sys.exit(1)

    if ((options.output != None) and
        (len(audiofiles) != 1)):
        print >>sys.stderr,'*** You may specify only 1 input file for use with -o'
        sys.exit(1)


    #if we're using an XMCD file, use that file for MetaData
    if (options.xmcd != None):
        try:
            xmcd = audiotools.parse_xmcd_file(options.xmcd)
        except audiotools.XMCDException:
            print >>sys.stderr,"*** Invalid XMCD file"
            sys.exit(1)
    else: #if we're not using an XMCD file, use the AudioFile objects' data
        xmcd = None

    quality = options.quality
    max_processes = options.max_processes


    if (options.output == None):
        #the default encoding method, without an output file

        base_directory = options.dir

        queue = audiotools.ExecQueue()
        encoded_filenames = []

        for audiofile in audiofiles:
            try:
                track_number = audiofile.track_number()
                if (xmcd is not None):
                    filename = os.path.join(
                                base_directory,
                                AudioType.track_name(track_number,
                                                     xmcd[track_number]))

                    audiotools.make_dirs(filename)

                    queue.execute(convert_file,
                                  (AudioType,
                                   filename,
                                   audiofile,
                                   xmcd[track_number],
                                   quality))
                    encoded_filenames.append(filename)
                else:
                    filename = os.path.join(
                                base_directory,
                                AudioType.track_name(track_number,
                                                     audiofile.get_metadata()))

                    audiotools.make_dirs(filename)

                    queue.execute(convert_file,
                                  (AudioType,
                                   filename,
                                   audiofile,
                                   audiofile.get_metadata(),
                                   quality))
                encoded_filenames.append(filename)
            except KeyError:
                continue

        queue.run(max_processes)

        if (options.add_replay_gain and AudioType.can_add_replay_gain()):
            print >>sys.stderr,"* Adding ReplayGain metadata.  This may take some time."
            AudioType.add_replay_gain(encoded_filenames)
    else:
        #encoding only a single file
        audiofile = audiofiles[0]

        if (xmcd != None):
            metadata = audiofile.track_number()
        else:
            metadata = audiofile.get_metadata()

        convert_file(AudioType,
                     options.output,
                     audiofile,
                     metadata,
                     quality,
                     False)

